﻿/**
 * Copyright(c) Live2D Inc. All rights reserved.
 *
 * Use of this source code is governed by the Live2D Open Software license
 * that can be found at https://www.live2d.com/eula/live2d-open-software-license-agreement_en.html.
 */

#include "LAppView.hpp"
#include <math.h>
#include <string>
#include "LAppPal.hpp"
#include "LAppDelegate.hpp"
#include "LAppLive2DManager.hpp"
#include "LAppTextureManager.hpp"
#include "LAppDefine.hpp"
#include "TouchManager_Common.hpp"
#include "LAppSprite.hpp"
#include "LAppSpriteShader.hpp"
#include "LAppModel.hpp"

using namespace std;
using namespace LAppDefine;

LAppView::LAppView() : LAppView_Common(),
                       /*_back(NULL),
                       _gear(NULL),
                       _power(NULL),*/
                       _renderSprite(NULL),
                       _renderTarget(SelectTarget_None) {
	_clearColor[0] = 1.0f;
	_clearColor[1] = 1.0f;
	_clearColor[2] = 1.0f;
	_clearColor[3] = 0.0f;

	// タッチ関係のイベント管理
	_touchManager = new TouchManager_Common();
}

LAppView::~LAppView() {
	_renderBuffer.DestroyOffscreenSurface();
	if (_renderSprite) {
		delete _renderSprite;
	}
	if (_spriteShader) {
		delete _spriteShader;
	}
	if (_touchManager) {
		delete _touchManager;
	}
	/*if (_back)
	{
		delete _back;
	}
	if (_gear)
	{
		delete _gear;
	}
	if (_power)
	{
		delete _power;
	}*/
}

void LAppView::Initialize(int width, int height) {
	LAppView_Common::Initialize(width, height);

	// シェーダー作成
	_spriteShader = new LAppSpriteShader();

	// InitializeSprite();
}

void LAppView::Render() {
	// 画面サイズを取得する
	int maxWidth, maxHeight;
	//glfwGetWindowSize(LAppDelegate::GetInstance()->GetWindow(), &maxWidth, &maxHeight);
	maxWidth = LAppDelegate::GetInstance()->GetWindow()->width();
	maxHeight = LAppDelegate::GetInstance()->GetWindow()->height();
	/*_back->SetWindowSize(maxWidth, maxHeight);
	_gear->SetWindowSize(maxWidth, maxHeight);
	_power->SetWindowSize(maxWidth, maxHeight);*/

	/*_back->Render();
	_gear->Render();
	_power->Render();*/

	LAppLive2DManager *Live2DManager = LAppLive2DManager::GetInstance();

	Live2DManager->SetViewMatrix(_viewMatrix);

	// Cubism更新・描画
	Live2DManager->OnUpdate();

	// 各モデルが持つ描画ターゲットをテクスチャとする場合
	if (_renderTarget == SelectTarget_ModelFrameBuffer && _renderSprite) {
		const GLfloat uvVertex[] =
		{
			1.0f, 1.0f,
			0.0f, 1.0f,
			0.0f, 0.0f,
			1.0f, 0.0f,
		};

		for (csmUint32 i = 0; i < Live2DManager->GetModelNum(); i++) {
			LAppModel *model = Live2DManager->GetModel(i);
			float alpha = i < 1 ? 1.0f : model->GetOpacity(); // 片方のみ不透明度を取得できるようにする
			_renderSprite->SetColor(1.0f * alpha, 1.0f * alpha, 1.0f * alpha, alpha);

			if (model) {
				_renderSprite->SetWindowSize(maxWidth, maxHeight);
				_renderSprite->RenderImmidiate(model->GetRenderBuffer().GetColorBuffer(), uvVertex);
			}
		}
	}
}

void LAppView::InitializeSprite() {
	GLuint programId = _spriteShader->GetShaderId();

	int width, height;
	//glfwGetWindowSize(LAppDelegate::GetInstance()->GetWindow(), &width, &height);
	width = LAppDelegate::GetInstance()->GetWindow()->width();
	height = LAppDelegate::GetInstance()->GetWindow()->height();

	LAppTextureManager *textureManager = LAppDelegate::GetInstance()->GetTextureManager();
	const string resourcesPath = ResourcesPath;

	// string imageName = BackImageName;
	// LAppTextureManager::TextureInfo* backgroundTexture = textureManager->CreateTextureFromPngFile(resourcesPath + imageName);

	float x = width * 0.5f;
	float y = height * 0.5f;
	// float fWidth = static_cast<float>(backgroundTexture->width * 2.0f);
	// float fHeight = static_cast<float>(height * 0.95f);
	//_back = new LAppSprite(x, y, fWidth, fHeight, backgroundTexture->id, programId);

	// imageName = GearImageName;
	// LAppTextureManager::TextureInfo* gearTexture = textureManager->CreateTextureFromPngFile(resourcesPath + imageName);
	//
	// x = static_cast<float>(width - gearTexture->width * 0.5f);
	// y = static_cast<float>(height - gearTexture->height * 0.5f);
	// fWidth = static_cast<float>(gearTexture->width);
	// fHeight = static_cast<float>(gearTexture->height);
	//_gear = new LAppSprite(x, y, fWidth, fHeight, gearTexture->id, programId);

	// imageName = PowerImageName;
	// LAppTextureManager::TextureInfo* powerTexture = textureManager->CreateTextureFromPngFile(resourcesPath + imageName);
	//
	// x = static_cast<float>(width - powerTexture->width * 0.5f);
	// y = static_cast<float>(powerTexture->height * 0.5f);
	// fWidth = static_cast<float>(powerTexture->width);
	// fHeight = static_cast<float>(powerTexture->height);
	//_power = new LAppSprite(x, y, fWidth, fHeight, powerTexture->id, programId);

	// 画面全体を覆うサイズ
	x = width * 0.5f;
	y = height * 0.5f;
	_renderSprite = new LAppSprite(x, y, static_cast<float>(width), static_cast<float>(height), 0, programId);
}

void LAppView::OnTouchesBegan(float px, float py) const {
	_touchManager->TouchesBegan(px, py);
}

void LAppView::OnTouchesMoved(float px, float py) const {
	float viewX = this->TransformViewX(_touchManager->GetX());
	float viewY = this->TransformViewY(_touchManager->GetY());

	_touchManager->TouchesMoved(px, py);

	LAppLive2DManager *Live2DManager = LAppLive2DManager::GetInstance();
	Live2DManager->OnDrag(viewX, viewY);
}

void LAppView::OnTouchesEnded(float px, float py) const {
	// タッチ終了
	LAppLive2DManager *live2DManager = LAppLive2DManager::GetInstance();
	live2DManager->OnDrag(0.0f, 0.0f);
	{
		// シングルタップ
		float x = _deviceToScreen->TransformX(_touchManager->GetX()); // 論理座標変換した座標を取得。
		float y = _deviceToScreen->TransformY(_touchManager->GetY()); // 論理座標変換した座標を取得。
		if (DebugTouchLogEnable) {
			LAppPal::PrintLogLn("[APP]touchesEnded x:%.2f y:%.2f", x, y);
		}
		live2DManager->OnTap(x, y);
		/*
		// 歯車にタップしたか
		if (_gear->IsHit(px, py))
		{
			live2DManager->NextScene();
		}

		// 電源ボタンにタップしたか
		if (_power->IsHit(px, py))
		{
			LAppDelegate::GetInstance()->AppEnd();
		}
		*/
	}
}

void LAppView::PreModelDraw(LAppModel &refModel) {
	// 別のレンダリングターゲットへ向けて描画する場合の使用するフレームバッファ
	Csm::Rendering::CubismOffscreenSurface_OpenGLES2 *useTarget = NULL;

	if (_renderTarget != SelectTarget_None) {
		// 別のレンダリングターゲットへ向けて描画する場合

		//透過設定
		glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);

		// 使用するターゲット
		useTarget = (_renderTarget == SelectTarget_ViewFrameBuffer) ? &_renderBuffer : &refModel.GetRenderBuffer();

		if (!useTarget->IsValid()) {
			// 描画ターゲット内部未作成の場合はここで作成
			int width, height;
			//glfwGetWindowSize(LAppDelegate::GetInstance()->GetWindow(), &width, &height);
			width = LAppDelegate::GetInstance()->GetWindow()->width();
			height = LAppDelegate::GetInstance()->GetWindow()->height();
			if (width != 0 && height != 0) {
				// モデル描画キャンバス
				useTarget->CreateOffscreenSurface(static_cast<csmUint32>(width), static_cast<csmUint32>(height));
			}
		}

		// レンダリング開始
		useTarget->BeginDraw();
		useTarget->Clear(_clearColor[0], _clearColor[1], _clearColor[2], _clearColor[3]); // 背景クリアカラー
	}
}

void LAppView::PostModelDraw(LAppModel &refModel) {
	// 別のレンダリングターゲットへ向けて描画する場合の使用するフレームバッファ
	Csm::Rendering::CubismOffscreenSurface_OpenGLES2 *useTarget = NULL;

	if (_renderTarget != SelectTarget_None) {
		// 別のレンダリングターゲットへ向けて描画する場合

		// 使用するターゲット
		useTarget = (_renderTarget == SelectTarget_ViewFrameBuffer) ? &_renderBuffer : &refModel.GetRenderBuffer();

		// レンダリング終了
		useTarget->EndDraw();

		// LAppViewの持つフレームバッファを使うなら、スプライトへの描画はここ
		if (_renderTarget == SelectTarget_ViewFrameBuffer && _renderSprite) {
			const GLfloat uvVertex[] =
			{
				1.0f, 1.0f,
				0.0f, 1.0f,
				0.0f, 0.0f,
				1.0f, 0.0f,
			};

			_renderSprite->SetColor(1.0f * GetSpriteAlpha(0), 1.0f * GetSpriteAlpha(0), 1.0f * GetSpriteAlpha(0),
			                        GetSpriteAlpha(0));

			// 画面サイズを取得する
			int maxWidth, maxHeight;
			//glfwGetWindowSize(LAppDelegate::GetInstance()->GetWindow(), &maxWidth, &maxHeight);
			maxWidth = LAppDelegate::GetInstance()->GetWindow()->width();
			maxHeight = LAppDelegate::GetInstance()->GetWindow()->height();
			_renderSprite->SetWindowSize(maxWidth, maxHeight);

			_renderSprite->RenderImmidiate(useTarget->GetColorBuffer(), uvVertex);
		}
	}
}

void LAppView::SwitchRenderingTarget(SelectTarget targetType) {
	_renderTarget = targetType;
}

void LAppView::SetRenderTargetClearColor(float r, float g, float b) {
	_clearColor[0] = r;
	_clearColor[1] = g;
	_clearColor[2] = b;
}


float LAppView::GetSpriteAlpha(int assign) const {
	// assignの数値に応じて適当に決定
	float alpha = 0.4f + static_cast<float>(assign) * 0.5f; // サンプルとしてαに適当な差をつける
	if (alpha > 1.0f) {
		alpha = 1.0f;
	}
	if (alpha < 0.1f) {
		alpha = 0.1f;
	}

	return alpha;
}

void LAppView::ResizeSprite() {
	LAppTextureManager *textureManager = LAppDelegate::GetInstance()->GetTextureManager();
	if (!textureManager) {
		return;
	}

	// 描画領域サイズ
	int width, height;
	//glfwGetWindowSize(LAppDelegate::GetInstance()->GetWindow(), &width, &height);
	width = LAppDelegate::GetInstance()->GetWindow()->width();
	height = LAppDelegate::GetInstance()->GetWindow()->height();

	float x = 0.0f;
	float y = 0.0f;
	float fWidth = 0.0f;
	float fHeight = 0.0f;
	/*
	if (_back)
	{
		GLuint id = _back->GetTextureId();
		LAppTextureManager::TextureInfo* texInfo = textureManager->GetTextureInfoById(id);
		if (texInfo)
		{
			x = width * 0.5f;
			y = height * 0.5f;
			fWidth = static_cast<float>(texInfo->width * 2);
			fHeight = static_cast<float>(height) * 0.95f;
			_back->ResetRect(x, y, fWidth, fHeight);
		}
	}

	if (_power)
	{
		GLuint id = _power->GetTextureId();
		LAppTextureManager::TextureInfo* texInfo = textureManager->GetTextureInfoById(id);
		if (texInfo)
		{
			x = static_cast<float>(width - texInfo->width * 0.5f);
			y = static_cast<float>(texInfo->height * 0.5f);
			fWidth = static_cast<float>(texInfo->width);
			fHeight = static_cast<float>(texInfo->height);
			_power->ResetRect(x, y, fWidth, fHeight);
		}
	}

	if (_gear)
	{
		GLuint id = _gear->GetTextureId();
		LAppTextureManager::TextureInfo* texInfo = textureManager->GetTextureInfoById(id);
		if (texInfo)
		{
			x = static_cast<float>(width - texInfo->width * 0.5f);
			y = static_cast<float>(height - texInfo->height * 0.5f);
			fWidth = static_cast<float>(texInfo->width);
			fHeight = static_cast<float>(texInfo->height);
			_gear->ResetRect(x, y, fWidth, fHeight);
		}
	}
	*/
}
